﻿using Padsurface.CoreAudio.Common;
using Padsurface.CoreAudio.Constants;
using Padsurface.CoreAudio.Enumerations;
using Padsurface.CoreAudio.MultiMediaStructures;
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace Padsurface.CoreAudio.Wrappers.Model
{
    internal class AudioStreamUninitializedState : IAudioStreamState
    {
        public async Task Initialize(AudioStream context)
        {
            if (context == null) throw new ArgumentNullException("context");

            context.AudioClient = await context.AudioClientActivator.Activate();
            InitializeMixFormat(context);

            var audioSessionGuid = context.AudioSessionGuid;
            Marshal.ThrowExceptionForHR(
                context.AudioClient.Initialize(AudioClientShareMode.Shared, AudioClientStreamFlags.None, ReferenceTime.PerSecond, 0, context.MixFormat, ref audioSessionGuid));

            InitializeBufferSize(context);
            context.AudioCaptureClient = context.AudioCaptureClientActivator.Activate(context.AudioClient);

            context.SetState(new AudioStreamInitializedState());
        }

        public void Start(AudioStream context)
        {
            throw new InvalidOperationException();
        }

        public Task Stop(AudioStream context)
        {
            throw new InvalidOperationException();
        }

        private void InitializeMixFormat(AudioStream context)
        {
            IntPtr deviceFormatPointer;
            Marshal.ThrowExceptionForHR(context.AudioClient.GetMixFormat(out deviceFormatPointer));
            context.DeviceFormatPointer = deviceFormatPointer;

            var waveFormat = (WaveFormatEx)Marshal.PtrToStructure(deviceFormatPointer, typeof(WaveFormatEx));

            if (waveFormat.FormatTag == WaveFormatTags.Pcm)
                waveFormat.ExtraSize = 0;
            else if (waveFormat.FormatTag == WaveFormatTags.Extensible)
                waveFormat = (WaveFormatExtensible)Marshal.PtrToStructure(deviceFormatPointer, typeof(WaveFormatExtensible));

            context.MixFormat = waveFormat;
        }

        private void InitializeBufferSize(AudioStream context)
        {
            UInt32 bufferSize;
            Marshal.ThrowExceptionForHR(context.AudioClient.GetBufferSize(out bufferSize));

            context.BufferSize = bufferSize;
        }
    }
}